package com.tandashi.springbootstudy01.intercept;

import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.annotation.Order;
import org.springframework.core.env.Environment;
import org.springframework.stereotype.Component;

@Aspect
@Component
@Order(1)
@Slf4j
public class SentineInterceptor {

    //@within 对象级别 @annotation 方法级别
    @Pointcut("within(@org.springframework.stereotype.Controller *)")
    public void pointcut1() {
    }

    @Pointcut("within(@org.springframework.web.bind.annotation.RestController *)")
    public void pointcut2() {
    }

    @Around("pointcut1()||pointcut2()")
    public Object around(ProceedingJoinPoint joinPoint) throws Throwable {
        // 获取目标类名称
        String clazzName = joinPoint.getTarget().getClass().getSimpleName();
        // 获取目标类方法
        String methodName = joinPoint.getSignature().getName();
        // sourceName
        String sourceName = clazzName + "-" + methodName;

        long start = System.currentTimeMillis();
        Object ret = joinPoint.proceed();
        if(isLoggable(sourceName)){
            long used = System.currentTimeMillis() - start;
            log(used,clazzName,methodName,joinPoint.getArgs(),ret);
        }
        return ret;
    }

    private void log(long used, String clazzName, String methodName, Object[] params, Object ret) {
        try {
            String args = objectMapper.writeValueAsString(params);
            args = args.substring(1, args.length() - 1);
            log.warn("used {}ms {}.{}({}) - {}",used,clazzName,methodName,args,objectMapper.writeValueAsString(ret));
        } catch (Exception ignore) {
        }
    }

    private boolean isLoggable(String entry) {
        // uat 环境不打印
        if(!environment.acceptsProfiles("uat")){
            return true;
        }
        return false;
    }

    @Autowired
    private ObjectMapper objectMapper;

    @Autowired
    Environment environment;

}
